#include <iostream>

using namespace std;

/*
 * 通用的数组类
 *      1、可以对内置数据类型以及自定义数据类型的数据进行储存
 *      2、将数组中的数据储存到堆区
 *      3、构造函数中可以传入数组的容量
 *      4、提供对应的拷贝构造函数以及operator=防止浅拷贝问题
 *      5、提供尾插法和尾删法对数组中的数据进行增加和删除
 *      6、可以通过下标的方式访问数组中的元素
 *      7、可以获取数组中当前元素个数和数组的容量
 */

template<typename T>
class MyArray{
public:
    int arr_num;   // 数组中元素个数
    int arr_cap;   // 数组容量
    T ** arr;   // 数组中数据储存到堆区，所以数组中储存T的地址
    MyArray(int cap){
        this->arr_cap = cap;
        arr_num = 0;
        this->arr = new T * [cap];
    }
    // 拷贝构造函数
    MyArray(const MyArray &array){
        this->arr_num = array.arr_num;
        this->arr_cap = array.arr_cap;
        this->arr = new T * [this->arr_cap];
        for (int i = 0; i < array.arr_num; ++i) {
            this->arr[i] = new T(*array.arr[i]);
        }
    }
    // 运算符重载
    MyArray & operator= (const MyArray & array){
        // 先判断堆区是否有数据，如果有数据先释放堆区数据
        if (this->arr != nullptr){
            for (int i = 0; i < this->arr_num; ++i) {
                delete this->arr[i];
                this->arr[i] = nullptr;
            }
            delete[] this->arr;
            this->arr = nullptr;
        }
        this->arr_num = array.arr_num;
        this->arr_cap = array.arr_cap;
        this->arr = new T * [this->arr_cap];
        for (int i = 0; i < array.arr_num; ++i) {
            this->arr[i] = new T(*array.arr[i]);
        }
        return *this;
    }
    // 析构函数，释放堆空间
    ~MyArray(){
        if (this->arr_num > 0){
            for (int i = 0; i < this->arr_num; ++i) {
                delete this->arr[i];
                this->arr[i] = nullptr;
            }
            delete[] this->arr;
            this->arr = nullptr;
        }
    }
    // 尾部添加元素
    void addObject(T obj){
        if(this->arr_num>= this->arr_cap){
            cout << "数组已满" << endl;
            return;
        }
        this->arr[this->arr_num] = new T(obj);
        this->arr_num++;
    }
    // 尾部删除元素
    void delObject(){
        if(this->arr_num <= 0){
            cout << "数组为空" << endl;
            return;
        }
        this->arr_num--;
        delete this->arr[this->arr_num];
        this->arr[this->arr_num] = nullptr;
    }

    // 通过下标方式访问元素
    T & operator[](int index){
        return *this->arr[index];
    }
    void showArr(){
        if (this->arr_num == 0){
            cout << "数组为空" << endl;
            return;
        }
        for (int i = 0; i < this->arr_num; ++i) {
            cout << "第" << i+1 << "位元素:" << *this->arr[i] << endl;
        }
    }
};

void test01(){
    MyArray<string> arr(10);
    arr.showArr();
    arr.addObject("a");
    arr.addObject("1");
    arr.addObject("dea");
    arr.addObject("465");
    arr.addObject("fsef");
    MyArray<string> arr2(arr);
    MyArray<string> arr3(100);
    arr3 = arr;
    arr.showArr();
    arr.delObject();
    arr.showArr();
    arr.delObject();
    arr.showArr();
    arr.delObject();
    arr.showArr();
    arr.delObject();
    arr.showArr();
    arr.delObject();
    arr.showArr();
    arr.delObject();
    arr.showArr();
    cout << "arr2:" << endl;
    arr2.showArr();
    cout << "arr3:" << endl;
    arr3.showArr();
    cout << arr3[3] << endl;
}

int main() {

    test01();

    return 0;
}
